import struct
import numpy as np
from PIL import Image


def png_to_bmp_rgb565(input_path, output_path, target_size=(410, 502)):
    """
    将PNG转换为RGB565格式的BMP文件
    参数：
        input_path: 输入PNG文件路径
        output_path: 输出BMP文件路径
        target_size: 目标尺寸 (width, height)
    """
    # 加载并调整图像尺寸
    img = Image.open(input_path).convert("RGB")
    img = img.resize(target_size, Image.Resampling.LANCZOS)

    # 将图像数据转换为numpy数组
    rgb_array = np.array(img)

    # 将RGB888转换为RGB565
    def rgb888_to_rgb565(r, g, b):
        return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3)

    # 转换整个图像数组
    height, width = rgb_array.shape[:2]
    rgb565_data = np.zeros((height, width), dtype=np.uint16)
    for y in range(height):
        for x in range(width):
            r, g, b = rgb_array[y, x]
            rgb565_data[y, x] = rgb888_to_rgb565(r, g, b)

    # BMP文件头结构
    file_header = struct.pack(
        '<2sI4xI',
        b'BM',  # 文件类型
        54 + width * height * 2,  # 文件大小
        54  # 数据偏移量
    )

    # BMP信息头 (BITMAPINFOHEADER)
    info_header = struct.pack(
        '<IIiHHIIIIII',
        40,  # 信息头大小
        width,  # 图像宽度
        -height,  # 图像高度（负数表示从上到下存储）
        1,  # 颜色平面数
        16,  # 每像素位数
        0,  # 压缩方式 (BI_RGB)
        width * height * 2,  # 图像数据大小
        2835,  # 水平分辨率 (72 DPI)
        2835,  # 垂直分辨率
        0,  # 调色板颜色数
        0  # 重要颜色数
    )

    # 写入BMP文件
    with open(output_path, 'wb') as f:
        f.write(file_header)
        f.write(info_header)
        f.write(rgb565_data.tobytes())

if __name__ == "__main__":
    # 使用示例
    png_to_bmp_rgb565('input.png', 'output.bmp', (410, 502))